/*=============================================================================
PostProcessGame : game related post processing
Copyright (c) 2001 Crytek Studios. All Rights Reserved.

Revision history:
* 23/02/2005: Re-factored/Converted to CryEngine 2.0 by Tiago Sousa
* Created by Tiago Sousa

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include "I3DEngine.h"
#include "D3DPostProcess.h"

#pragma warning(disable: 4244)

/////////////////////////////////////////////////////////////////////////////////////////////////////
// Game/Hud specific post-processing
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool CD3D9Renderer::FX_CustomRenderScene( bool bEnable )
{
  if(bEnable)
  {
    PostProcessUtils().Log(" +++ Begin custom render scene +++ \n"); 
		if( CRenderer::CV_r_customvisions == 1)
		{
			CTexture::s_ptexBackBuffer->SetRenderTargetTile(1);

			FX_PushRenderTarget(0, CTexture::s_ptexBackBuffer, &gcpRendD3D->m_DepthBufferOrig);
			RT_SetViewport(0, 0, GetWidth(), GetHeight());                        
			ColorF clearColor(0, 0, 0, 0);
			EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor); // //FRT_CLEAR_DEPTH|
		}

    m_RP.m_PersFlags2 |= RBPF2_CUSTOM_RENDER_PASS;
  }
  else  
  { 
		if( CRenderer::CV_r_customvisions == 1)
		{
		  FX_PopRenderTarget(0);    
			CTexture::s_ptexBackBuffer->SetRenderTargetTile(0);
		}

    FX_ResetPipe();     

    PostProcessUtils().Log(" +++ End custom render scene +++ \n"); 

    RT_SetViewport(0, 0, gcpRendD3D->GetWidth(), gcpRendD3D->GetHeight());

    m_RP.m_PersFlags2 &= ~RBPF2_CUSTOM_RENDER_PASS;
  }

  return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CHudSilhouettes::Render()
{
	PROFILE_LABEL_PUSH( "HUD_SILHOUETTES" );

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);
	
	float fBlendParam = clamp_tpl<float>( m_pAmount->GetParam(), 0.0f, 1.0f) ;
  float fType = m_pType->GetParam();

	///////////////////////////////////////////////////////////////////////////////////////////////////
	// tint directly backbuffer when needed (saves 1 resolve)

	if( 0 && fType )
	{
		static CCryNameTSCRC pTechSilhouettesName("BinocularViewTinting");

		GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechSilhouettesName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

		gRenDev->FX_SetState(GS_NODEPTHTEST  | GS_BLSRC_DSTCOL | GS_BLDST_ZERO); 

		// Set PS default params
		Vec4 pParams= Vec4(0, 0, 0, fBlendParam);
		static CCryNameR pParamName("psParams");
		CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamName, &pParams, 1);

		GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

		GetUtils().ShEndPass();
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////
	// Render highlighted geometry/silhouettes

	{
		PROFILE_LABEL_PUSH( "HUD_SILHOUETTES_ENTITIES_PASS" );

		gcpRendD3D->Set2DMode(false, 1, 1);





		// render to texture all masks
		gcpRendD3D->FX_ProcessPostRenderLists(FB_CUSTOM_RENDER);





		gcpRendD3D->Set2DMode(true, 1, 1);

		PROFILE_LABEL_POP( "HUD_SILHOUETTES_ENTITIES_PASS" );
	}

	if( CRenderer::CV_r_customvisions == 2 )
		return;

  gcpRendD3D->RT_SetViewport(PostProcessUtils().m_pScreenRect.left, PostProcessUtils().m_pScreenRect.top, PostProcessUtils().m_pScreenRect.right, PostProcessUtils().m_pScreenRect.bottom); 
  PostProcessUtils().m_pCurDepthSurface = &gcpRendD3D->m_DepthBufferOrig;

  CTexture *pScreen = CTexture::s_ptexBackBuffer;
  CTexture *pMask = CTexture::s_ptexBlack;
  CTexture *pMaskBlurred = CTexture::s_ptexBlack;

  // skip processing, nothing was added to mask
  if( ( SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD) | SRendItem::BatchFlags(EFSLIST_TRANSP, gRenDev->m_RP.m_pRLD) ) & FB_CUSTOM_RENDER)
  {
    // could render directly to frame buffer ? save 1 resolve - no glow though
    {






      // store silhouettes/signature temporary render target, so that we can post process this afterwards
      gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexBackBufferScaled[0], NULL);
      gcpRendD3D->RT_SetViewport(0, 0, CTexture::s_ptexBackBufferScaled[0]->GetWidth(), CTexture::s_ptexBackBufferScaled[0]->GetHeight());

      static CCryNameTSCRC pTech1Name("BinocularView");
      PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTech1Name, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

      gRenDev->FX_SetState(GS_NODEPTHTEST);

      // Set PS default params
      Vec4 pParams= Vec4(0, 0, 0, (!fType)? 1.0f : 0.0f);
      static CCryNameR pParamName("psParams");
      CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamName, &pParams, 1); 

      PostProcessUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_POINT);   
      PostProcessUtils().SetTexture(CTexture::s_ptexZTarget, 1, FILTER_POINT);   
      PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexSceneTarget->GetWidth(), CTexture::s_ptexSceneTarget->GetHeight());

      PostProcessUtils().ShEndPass();
      gcpRendD3D->FX_PopRenderTarget(0);    





      pMask = CTexture::s_ptexBackBufferScaled[0];
			pMaskBlurred = CTexture::s_ptexBackBufferScaled[1];
    }

		////////////////////////////////////////////////////////////////////////////////////////////////
		// compute glow

		{
			CTexture::s_ptexBackBufferScaled[1]->SetRenderTargetTile(1);

			GetUtils().StretchRect(CTexture::s_ptexBackBufferScaled[0], CTexture::s_ptexBackBufferScaled[1]);

			// blur - for glow
//			GetUtils().TexBlurGaussian(CTexture::s_ptexBackBufferScaled[0], 1, 1.5f, 2.0f, false);                  
			GetUtils().TexBlurIterative(CTexture::s_ptexBackBufferScaled[1], 1, false);                  

			gcpRendD3D->RT_SetViewport(0, 0, gcpRendD3D->GetWidth(), gcpRendD3D->GetHeight());

			CTexture::s_ptexBackBufferScaled[1]->SetRenderTargetTile(0);
		}

		////////////////////////////////////////////////////////////////////////////////////////////////
		// finally add silhouetes to screen

		{
			static CCryNameTSCRC pTechSilhouettesName("BinocularViewSilhouettes");

			GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechSilhouettesName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

			gRenDev->FX_SetState(GS_NODEPTHTEST  | GS_BLSRC_ONE | GS_BLDST_ONE); 

			GetUtils().SetTexture(pMask, 0);   
			GetUtils().SetTexture(pMaskBlurred, 1);   

			// Set PS default params
			Vec4 pParams= Vec4(0, 0, 0, fBlendParam * 0.33f);
			static CCryNameR pParamName("psParams");
			CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamName, &pParams, 1);

			GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

			GetUtils().ShEndPass();
		}
  }

  gcpRendD3D->RT_SetViewport(GetUtils().m_pScreenRect.left, GetUtils().m_pScreenRect.top, GetUtils().m_pScreenRect.right, GetUtils().m_pScreenRect.bottom); 
	
	PROFILE_LABEL_POP( "HUD_SILHOUETTES" );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CAlienInterference::Render()
{
	PROFILE_LABEL_PUSH( "ALIEN_INTERFERENCE" );

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);

  float fAmount = m_pAmount->GetParam();

  static CCryNameTSCRC pTechName("AlienInterference");
  PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES);   

  gcpRendD3D->FX_SetState(GS_NODEPTHTEST);   

  Vec4 vParams=Vec4(1, 1, (float)PostProcessUtils().m_iFrameCounter, fAmount);    
  static CCryNameR pParamName("psParams");
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamName, &vParams, 1);

	static CCryNameR pParamAlienInterferenceName("AlienInterferenceTint");
	vParams = m_pTintColor->GetParamVec4();
	vParams.x *= 2.0f; vParams.y *= 2.0f; vParams.z *= 2.0f;
	CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamAlienInterferenceName, &vParams, 1);

  PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());



  PostProcessUtils().ShEndPass();   

	PROFILE_LABEL_POP( "ALIEN_INTERFERENCE" );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CScreenFrost::Render()
{
  float fAmount = m_pAmount->GetParam();

  if(fAmount<=0.02f) 
  {
    m_fRandOffset = ((float) cry_rand() / (float) RAND_MAX); 
    return;
  }

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);

  float fCenterAmount = m_pCenterAmount->GetParam();

  PostProcessUtils().StretchRect(CTexture::s_ptexBackBuffer, CTexture::s_ptexBackBufferScaled[1]);    

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // display frost
  static CCryNameTSCRC pTechName("ScreenFrost");
  PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES);   

  gcpRendD3D->FX_SetState(GS_NODEPTHTEST);   

  static CCryNameR pParam0Name("screenFrostParamsVS");
  static CCryNameR pParam1Name("screenFrostParamsPS");

  PostProcessUtils().ShSetParamVS(pParam0Name, Vec4(1, 1, 1, m_fRandOffset));
  PostProcessUtils().ShSetParamPS(pParam1Name, Vec4(1, 1, fCenterAmount, fAmount));

  PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

  PostProcessUtils().ShEndPass();   
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool CFlashBang::Preprocess()
{

  float fActive = m_pActive->GetParam();
  if( fActive || m_fSpawnTime)
  {
    if( fActive )
      m_fSpawnTime = 0.0f;

    m_pActive->SetParam( 0.0f );

    return true;
  }


  return false;
}

void CFlashBang::Render()
{
  float fTimeDuration = m_pTime->GetParam();
  float fDifractionAmount = m_pDifractionAmount->GetParam();
  float fBlindTime = m_pBlindAmount->GetParam();

  if( !m_fSpawnTime )
  {
    m_fSpawnTime = PostProcessUtils().m_pTimer->GetCurrTime();

    // Create temporary ghost image and capture screen
    SAFE_DELETE( m_pGhostImage );

    m_pGhostImage = new SDynTexture(CTexture::s_ptexBackBuffer->GetWidth()>>1, CTexture::s_ptexBackBuffer->GetHeight()>>1, eTF_A8R8G8B8, eTT_2D,  FT_STATE_CLAMP, "GhostImageTempRT");  
    m_pGhostImage->Update( CTexture::s_ptexBackBuffer->GetWidth()>>1, CTexture::s_ptexBackBuffer->GetHeight()>>1 );

    if( m_pGhostImage && m_pGhostImage->m_pTexture )
    {
      PostProcessUtils().StretchRect(CTexture::s_ptexBackBuffer, m_pGhostImage->m_pTexture);        
    }
  } 

  // Update current time
  float fCurrTime = (PostProcessUtils().m_pTimer->GetCurrTime() - m_fSpawnTime) / fTimeDuration;  

  // Effect finished
  if( fCurrTime > 1.0f )
  {
    m_fSpawnTime = 0.0f;
    m_pActive->SetParam(0.0f);

    SAFE_DELETE( m_pGhostImage );

    return;
  }  

  // make sure to update dynamic texture if required
  if( m_pGhostImage && !m_pGhostImage->m_pTexture )
  {
    m_pGhostImage->Update( CTexture::s_ptexBackBuffer->GetWidth()>>1, CTexture::s_ptexBackBuffer->GetHeight()>>1 );
  }

  if( !m_pGhostImage || !m_pGhostImage->m_pTexture )
  {        
    return;
  }

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);

  //////////////////////////////////////////////////////////////////////////////////////////////////    
  static CCryNameTSCRC pTechName("FlashBang");
  PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES|FEF_DONTSETTEXTURES);   

  gcpRendD3D->FX_SetState(GS_NODEPTHTEST);   

  float fLuminance = 1.0f  - fCurrTime; //PostProcessUtils().InterpolateCubic(0.0f, 1.0f, 0.0f, 1.0f, fCurrTime);

  // opt: some pre-computed constants
  Vec4 vParams = Vec4( fLuminance, fLuminance * fDifractionAmount, 3.0f * fLuminance * fBlindTime, fLuminance );                
  static CCryNameR pParamName("vFlashBangParams");
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamName, &vParams, 1);

  PostProcessUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_POINT);     
  PostProcessUtils().SetTexture(m_pGhostImage->m_pTexture, 1, FILTER_LINEAR);     

  PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

  PostProcessUtils().ShEndPass();   
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CFilterKillCamera::Render()
{
	PROFILE_LABEL_PUSH( "KILL_CAMERA" );

	PROFILE_SHADER_START

	// Update time
	float frameTime = PostProcessUtils().m_pTimer->GetFrameTime();
	m_blindTimer += frameTime;

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);

	float grainStrength = m_pGrainStrength->GetParam();
	Vec4 chromaShift = m_pChromaShift->GetParamVec4(); // xyz = offset, w = strength
	Vec4 vignette = m_pVignette->GetParamVec4(); // xy = screen scale, z = radius, w = blind noise vignette scale
	Vec4 colorScale = m_pColorScale->GetParamVec4();

	float inverseVignetteRadius = 1.0f / clamp_tpl<float>(vignette.z*2.0f, 0.001f, 2.0f); 
	Vec2 vignetteScreenScale(max(vignette.x,0.0f),max(vignette.y,0.0f));

	// Blindness
	Vec4 blindness = m_pBlindness->GetParamVec4(); // x = blind duration, y = blind fade out duration, z = blindness grey scale, w = blind noise min scale
	float blindDuration = max(blindness.x,0.0f);
	float blindFadeOutDuration = max(blindness.y,0.0f);
	float blindGreyScale = clamp_tpl<float>(blindness.z,0.0f,1.0f);
	float blindNoiseMinScale = clamp_tpl<float>(blindness.w,0.0f,10.0f);
	float blindNoiseVignetteScale = clamp_tpl<float>(vignette.w,0.0f,10.0f);

	float blindAmount = 0.0f;
	if(m_blindTimer < blindDuration)
	{
		blindAmount = 1.0f;
	}
	else
	{
		float blindFadeOutTimer = m_blindTimer - blindDuration;
		if(blindFadeOutTimer < blindFadeOutDuration)
		{
			blindAmount = 1.0f - (blindFadeOutTimer / blindFadeOutDuration);
		}
	}

	// Rendering
	PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, m_techName, FEF_DONTSETSTATES);   

	gcpRendD3D->FX_SetState(GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);

	int x = 0;
	int y = 0;
	int width = 0;
	int height = 0;
	gcpRendD3D->GetViewport(&x, &y, &width, &height);

	// Set PS default params
	const int PARAM_COUNT = 4;
	Vec4 pParams[PARAM_COUNT];

	// psParams[0] - xy = Rand lookup, zw = vignetteScreenScale * invRadius
	pParams[0].x = (cry_rand()%1024) / ((float)width);
	pParams[0].y = (cry_rand()%1024) / ((float)height);
	pParams[0].z = vignetteScreenScale.x*inverseVignetteRadius;
	pParams[0].w = vignetteScreenScale.y*inverseVignetteRadius;

	// psParams[1] - xyz = color scale, w = grain strength
	pParams[1].x = colorScale.x;
	pParams[1].y = colorScale.y;
	pParams[1].z = colorScale.z;
	pParams[1].w = grainStrength;

	// psParams[2] - xyz = chroma shift, w = chroma shift color strength
	pParams[2] = chromaShift;

	// psParams[3] - x = blindAmount, y = blind grey scale, z = blindNoiseVignetteScale, w = blindNoiseMinScale
	pParams[3].x = blindAmount;
	pParams[3].y = blindGreyScale;
	pParams[3].z = blindNoiseVignetteScale;
	pParams[3].w = blindNoiseMinScale;

	CShaderMan::m_shPostEffects->FXSetPSFloat(m_paramName, pParams, PARAM_COUNT); 

	PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

	PostProcessUtils().ShEndPass();   

	PROFILE_SHADER_END

	PROFILE_LABEL_POP( "KILL_CAMERA" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

enum ENanoGlassDebugView
{
	eNANO_GLASS_DEBUG_VIEW_Off = 0,
	eNANO_GLASS_DEBUG_VIEW_WireFrame
};

void CNanoGlass::Render()
{
	PROFILE_LABEL_PUSH( "NANO_GLASS_FILTER" );
	PROFILE_SHADER_START
	
	// Clear sample flags
	gcpRendD3D->m_RP.m_FlagsShader_RT &= ~(	g_HWSR_MaskBit[HWSR_SAMPLE0] | 
																					g_HWSR_MaskBit[HWSR_SAMPLE1] |
																					g_HWSR_MaskBit[HWSR_SAMPLE2] |
																					g_HWSR_MaskBit[HWSR_SAMPLE4] |
																					g_HWSR_MaskBit[HWSR_DEBUG1] );

	bool bDebugPass = false;
	RenderPass(bDebugPass);

#ifndef _RELEASE
	if(CRenderer::CV_r_PostProcessNanoGlassDebugView)
	{
		bDebugPass = true;
		RenderPass(bDebugPass);
	}
#endif

	PROFILE_SHADER_END
	PROFILE_LABEL_POP( "NANO_GLASS_FILTER" );
}

void CNanoGlass::RenderPass(bool bDebugPass)
{
	// Set PS default params
	const int PARAM_COUNT = 6;
	Vec4 psParams[PARAM_COUNT];
	Vec4 filter = m_pFilter->GetParamVec4(); // x = outlineStrength, y = mistAlpha, z = refractionScale, w = bBlurRefraction
	float refractionBlurScale = filter.w;
	float effectAlpha = m_pEffectAlpha->GetParam();
	float introAnimPos = m_pStartAnimPos->GetParam();
	float outroAnimPos = m_pEndAnimPos->GetParam();
	float brightness = m_pBrightness->GetParam();
	Vec4 movement0 = m_pMovement[0]->GetParamVec4();
	Vec4 movement1 = m_pMovement[1]->GetParamVec4();
	Vec4 vignette = m_pVignette->GetParamVec4(); // xy = vignetteScreenScale , zw = free

	// Calc vignette
	Vec2 vignetteScreenScale(max(vignette.x,0.0f),max(vignette.y,0.0f));

	// Update time (Use UI time as this is animated during menu)
	float frameTime = PostProcessUtils().m_pTimer->GetFrameTime(ITimer::ETIMER_UI);
	m_noiseTime += frameTime * movement1.z;
	m_time += frameTime * movement0.x;

	// Check existence of back buffer scaled
	CTexture* pBackBufferScaled = CTexture::s_ptexBackBufferScaled[2];
	if(pBackBufferScaled == NULL)
		return;

	// Set render target tile to 1 to avoid possibility of writing over current render target tile 
	// if it has not been resolved yet
	pBackBufferScaled->SetRenderTargetTile(1);

	// Set screen texture to use
	CTexture* pScreenTex = CTexture::s_ptexBackBuffer;

	// Optimized platform specific down sampling of texture












	if(refractionBlurScale > 0.0f)
	{
		// Stretch back buffer onto scaled version for blur
		GetUtils().StretchRect(CTexture::s_ptexBackBuffer, pBackBufferScaled, false, false, false, true);
		pScreenTex = pBackBufferScaled;
	}


	// psParams[0] - x = hexTexScale y = hexOutlineMin, z = vignetteTexOffset, w = vignetteSaturation
	psParams[0] = m_pHexParams->GetParamVec4();

	// psParams[1] - x = introAnimPos, y = outroAnimPos, z = time, w = brightness
	psParams[1].x = introAnimPos;
	psParams[1].y = outroAnimPos;
	psParams[1].z = m_time;
	psParams[1].w = brightness;

	// psParams[2] - x = noiseTime, y = movementWaveStrength, z = vignetteFallOffScale, w = movementWaveFrequency
	const float waveStrengthScale = 0.1f; // Use scalar here so post effect param is between 0 and 1
	psParams[2] = movement0;
	psParams[2].x = m_noiseTime;
	psParams[2].y *= waveStrengthScale;

	// psParams[3] - x = movementStrengthX, y = movementStrengthY, z = refractionScale, w = vignetteStrength
	const float noiseSpeedScale = 0.05f; // Use scalar here so post effect param is between 0 and 1
	psParams[3] = movement1;
	psParams[3].z = filter.z;

	// psParams[4] - x = outlineStrength, y = mistAlpha, zw = vignetteScreenScale
	psParams[4].x = filter.x;
	psParams[4].y = filter.y;
	psParams[4].z = vignetteScreenScale.x;
	psParams[4].w = vignetteScreenScale.y;

	// psParams[5] - xyz = hex Color, w = effect alpha
	Vec4 hexColor = m_pHexColor->GetParamVec4();
	psParams[5] = hexColor * hexColor.w;
	psParams[5].w = effectAlpha;

	// Setup shader
	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);
	CShaderMan::m_shPostEffects->FXSetPSFloat(m_paramName, psParams, PARAM_COUNT);

	const uint32 nThreadID = gcpRendD3D->m_RP.m_nProcessThreadID;
	SShaderTechnique *pShaderTech = CShaderMan::m_shPostEffectsGame->mfFindTechnique(m_shaderTechName);
	SRenderData &pRenderData = m_pRenderData[nThreadID];

	if(pRenderData.pRenderElement && pShaderTech)
	{	
		// Draw 3d mesh in 2d
		gcpRendD3D->Set2DMode(false, 1, 1);

		// Set scissor
		gcpRendD3D->FX_Commit(); 
		gcpRendD3D->EF_Scissor(true, 0, 0, gcpRendD3D->GetWidth(), gcpRendD3D->GetHeight());

		// Render state
		int32 nRenderState = GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;

		// Set intro flag
		if((introAnimPos > 0.0f) && (introAnimPos < 1.0f))
		{
			gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
		}

		// Set outro flag
		if((outroAnimPos > 0.0f) && (outroAnimPos < 1.0f))
		{
			gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
		}

		// Set movement wave flag
		if(psParams[2].y > 0.0f)
		{
			gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
		}

		// Set noise flag
		if((filter.y > 0.0f) || (hexColor.w > 0.0f))
		{
			gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE4];
		}

#ifndef _RELEASE
		// Turn on debug view in shader
		if(bDebugPass && CRenderer::CV_r_PostProcessNanoGlassDebugView)
		{
			gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG1];
			if(CRenderer::CV_r_PostProcessNanoGlassDebugView == eNANO_GLASS_DEBUG_VIEW_WireFrame)
			{
				nRenderState |= GS_WIREFRAME;
			}
		}
#endif

		GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, m_shaderTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

		// Set view proj matrix
		Matrix44A mObjCurr, mViewProj;
		C3DHud* p3DHUD = reinterpret_cast<C3DHud*>( PostEffectMgr()->GetEffect( ePFX_3DHUD ) );
		float fHUDFov = 55.0f;	// Safe default
		if ( p3DHUD )
		{
			CEffectParam* pFov = p3DHUD->GetFov();
			if ( pFov)
			{
				fHUDFov = clamp_tpl<float>(pFov->GetParam(),1.0f,180.0f);
			}
		}

		// Precalculate the pixel aspect ratio for the nano glass on PC so as to better fit it to the screen
		float fInvPAR = 1.0f;
#if !defined(XENON) && !defined(PS3)
		float fBackBufferRatio = (float)CTexture::s_ptexBackBuffer->GetWidth() / (float)CTexture::s_ptexBackBuffer->GetHeight();
		float f16_9 = 16.0f / 9.0f;
		fInvPAR = f16_9 / fBackBufferRatio;
#endif

		// Patch projection matrix to have HUD FOV
		mViewProj = gRenDev->m_ProjMatrix;
		float aspect = (mViewProj.m11 / mViewProj.m00) * fInvPAR;
		float h = 1 / tanf(DEG2RAD(fHUDFov / 2));
		mViewProj.m00 = h / aspect;
		mViewProj.m11 = h;

		mViewProj.Multiply(gRenDev->m_ViewMatrix, mViewProj);
		mObjCurr.Transpose(pRenderData.pRenderObject->m_II.m_Matrix);   			
		mViewProj.Multiply(mObjCurr, mViewProj);
		mViewProj.Transpose();

		CShaderMan::m_shPostEffectsGame->FXSetVSFloat(m_viewProjMatrixParamName, (Vec4 *) mViewProj.GetData(), 4);		

		// Set render state
		gcpRendD3D->FX_SetState( nRenderState );
		gcpRendD3D->SetCullMode( R_CULL_BACK );

		// Set ps params
		CShaderMan::m_shPostEffects->FXSetPSFloat(m_paramName, psParams, PARAM_COUNT);

		// Set textures
		GetUtils().SetTexture(m_pHexNormal, 0, FILTER_LINEAR, TADDR_WRAP);
		GetUtils().SetTexture(m_pHexOutline, 1, FILTER_LINEAR, TADDR_MIRROR);
		GetUtils().SetTexture(pScreenTex, 2, FILTER_LINEAR,1,true);
		GetUtils().SetTexture(m_pNoise,3,FILTER_LINEAR, TADDR_WRAP);

		// Draw mesh
		CD3D9Renderer *const __restrict rd = gcpRendD3D;
		CREMeshImpl *pRenderMesh = (CREMeshImpl*) pRenderData.pRenderElement;

		// Create/Update vertex buffer stream
		if( pRenderMesh->m_pRenderMesh )
			pRenderMesh->m_pRenderMesh->CheckUpdate( pRenderMesh->m_pRenderMesh->_GetVertexFormat(), 0);

		gcpRendD3D->m_RP.m_pRE = const_cast<CRendElementBase*>( pRenderData.pRenderElement );
		if( gcpRendD3D->FX_CommitStreams(&pShaderTech->m_Passes[0], true) )
		{
			gcpRendD3D->m_RP.m_FirstVertex = pRenderMesh->m_nFirstVertId;
			gcpRendD3D->m_RP.m_FirstIndex = pRenderMesh->m_nFirstIndexId;
			gcpRendD3D->m_RP.m_RendNumIndices = pRenderMesh->m_nNumIndices;
			gcpRendD3D->m_RP.m_RendNumVerts = pRenderMesh->m_nNumVerts;
			gcpRendD3D->m_RP.m_pRE->mfDraw(CShaderMan::m_shPostEffectsGame, &pShaderTech->m_Passes[0]);
		}

		gcpRendD3D->Set2DMode(true, 1, 1);
		gcpRendD3D->EF_Scissor(false, 0, 0, 0, 0);

		gcpRendD3D->FX_Flush(); 

		PostProcessUtils().ShEndPass();   
	}

	pBackBufferScaled->SetRenderTargetTile(0);
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

void CHUDHitEffect::Update()
{

}

void CHUDHitEffect::SpawnHitEffect()
{
	const float	fHitStrength	= m_pHitStrength->GetParam();
	const float	fHitSpeed		= m_pHitSpeed->GetParam();
	const Vec4	vHitDirection	= m_pHitDirection->GetParamVec4();

	const float	fFadeInTime		= m_pCriticalSaturation->GetParam();
	const float	fDisplayTime	= m_pDisplayTime->GetParam();
	const float	fFadeOutTime	= m_pCriticalBrightness->GetParam();
	const float	fAnimSpeed		= m_pAnimSpeed->GetParam();

	//something to spawn?
	if(	fHitStrength <= EPSILON
	&&	fHitSpeed <= EPSILON
	&&	vHitDirection.w <= EPSILON)
		return;

	uint16	iNewImpact = (m_iCurrent1stImpact + m_iActiveImpacts) % sm_HitImpactCount;
	SHitImpact& hitImpact = m_aHitImpacts[iNewImpact];

	//spawn new
	hitImpact = SHitImpact(fHitStrength, fHitSpeed*2, vHitDirection);	//ctor decides if started or not

	if(hitImpact._bStarted)
	{
		++m_iActiveImpacts;
		m_iActiveImpacts %= sm_HitImpactCount;
	}

	//reset
	m_pHitDirection->SetParamVec4(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
	m_pHitStrength->SetParam(0.0f);
	m_pHitSpeed->SetParam(0.0f);
}

void CHUDHitEffect::UpdateCoverage()
{
	//compute current coverage
	const float	fDeltaTime		= PostProcessUtils().m_pTimer->GetFrameTime();
	const float	fDisplayTime	= m_pDisplayTime->GetParam();	
	const float	fAnimSpeed		= m_pAnimSpeed->GetParam();

	float fMaxCumulTime			= 0.0f;
	float fMaxImpactSpeed		= 0.0f;

	const CCamera&	camera = gcpRendD3D->GetCamera();	
	const Matrix34&	mViewMatrix = camera.GetViewMatrix();

	for(int i = 0; i < sm_HitImpactCount; ++i)
	{
		SHitImpact& hitImpact = m_aHitImpacts[i];
		if(hitImpact._bStarted)
		{
			if(hitImpact._fCumulTime <= fDisplayTime)	//we could test for the position, but because of LERP below, this is easier
			{
				const float fProgress = SATURATE(hitImpact._fCumulTime / fDisplayTime);
				
				const Vec3	vCurrentHitPosition(
					LERP((-hitImpact._vHitDirection.x), (-hitImpact._vHitDirection.x * 0.3f), fProgress),
					LERP((-hitImpact._vHitDirection.y), (-hitImpact._vHitDirection.y * 0.3f), fProgress),
					LERP((-hitImpact._vHitDirection.z), (-hitImpact._vHitDirection.z * 0.3f), fProgress));				
				const Vec3	vCurrentHitPosition_t( mViewMatrix.TransformVector(vCurrentHitPosition) );		//orientation only
				hitImpact._vCurrentPosition.x = vCurrentHitPosition_t.x;
				hitImpact._vCurrentPosition.y = vCurrentHitPosition_t.y;
				hitImpact._vCurrentPosition.z = vCurrentHitPosition_t.z;

				if(!hitImpact._bFlashPosInited)
				{
					const Vec3	vInitialFlashPosition(
						-hitImpact._vHitDirection.x,
						-hitImpact._vHitDirection.y,
						-hitImpact._vHitDirection.z);
					const Vec3	vInitialFlashPosition_t( mViewMatrix.TransformVector(vInitialFlashPosition) );		//orientation only
					Vec2		vFlashScreenSpacePos(vInitialFlashPosition_t.x, vInitialFlashPosition_t.y);
					vFlashScreenSpacePos = vFlashScreenSpacePos.Normalize() * 0.99f;
					hitImpact._vFlashPosition.x = vFlashScreenSpacePos.x;
					hitImpact._vFlashPosition.y = vFlashScreenSpacePos.y;
					hitImpact._vFlashPosition.z = 0.0f;
					hitImpact._vFlashPosition.w = 1.0f;
					hitImpact._bFlashPosInited = true;
				}
				hitImpact._fFlashDrawTime	-= fDeltaTime;
				hitImpact._fCumulTime		+= fDeltaTime * hitImpact._fImpactSpeed * fAnimSpeed;	//update last
			}
			else
			{
				//reset
				hitImpact = SHitImpact();
			}
			fMaxCumulTime	= max(fMaxCumulTime, hitImpact._fCumulTime);
			fMaxImpactSpeed	= max(fMaxImpactSpeed, hitImpact._fImpactSpeed);
		}
	}
}


inline void	DoUpdateVarT(float& rfVarT, const float fVarOffset, const float fHealthLevel, const float fVarDelta)
{
	const	float	fVarTarget	= SATURATE(fHealthLevel / max(fVarOffset, EPSILON));	//data in [0..1]
	const	float	fVarDiff	= fVarTarget - rfVarT;

	rfVarT += min(fVarDelta, abs(fVarDiff)) * SIGN(fVarDiff);
}

void	CHUDHitEffect::UpdateHealth()
{
	///- general interpolation method
	///		varOffset	:= decrease if health below this level
	///		varTarget	:= healthLevel < varOffset ? healthLevel / varOffset : 1;
	///						equivalentTo: saturate(healthLevel / varOffset);
	///		varT		:= SIGN(varTarget - varT) * abs(varTarget - varT) * deltaTime * speed;
	///	at last:
	///		var			:= functional_curve(varT);
	///-/

	const	float	fHealthLevel	= SATURATE(m_pHealthLevel->GetParam());			//data in [0..1]
	const	float	fAnimSpeed		= m_pAnimSpeed->GetParam();
	const	float	fDeltaTime		= PostProcessUtils().m_pTimer->GetFrameTime();

	//update linear interpolation values
	DoUpdateVarT(m_fNanoLevelT,	 SATURATE(m_pHealthNanoOffset->GetParam()),		fHealthLevel, fAnimSpeed * fDeltaTime * 32.0f * LERP(2.0f, 1.0f, fHealthLevel));
	DoUpdateVarT(m_fVeinsLevelT, SATURATE(m_pHealthVeinsOffset->GetParam()),	fHealthLevel, fAnimSpeed * fDeltaTime * 8.0f * LERP(4.0f, 1.0f, fHealthLevel));
	DoUpdateVarT(m_fColorLevelT, SATURATE(m_pColorFadeOffset->GetParam()),		fHealthLevel, fAnimSpeed * fDeltaTime * 32.0f * LERP(2.0f, 1.0f, fHealthLevel));
	DoUpdateVarT(m_fFlickerFrequencyT, 1.0f, fHealthLevel, fAnimSpeed * fDeltaTime * 16.0f);

	//apply curve for final interpolation result
	const	float	fNanoLevelFadeOut = 0.85f;
	m_fNanoLevel	= SATURATE(m_fNanoLevelT < fNanoLevelFadeOut ? 0.0f : LERP(0.0f, 1.0f, (m_fNanoLevelT - fNanoLevelFadeOut) / (1-fNanoLevelFadeOut)));
	
	const	float	fVeinsLevelFadeOut = 0.6f;
	m_fVeinsLevel	= SATURATE(m_fVeinsLevelT < fVeinsLevelFadeOut ? 0.0f : LERP(0.0f, 1.0f, (m_fVeinsLevelT - fVeinsLevelFadeOut) / (1-fVeinsLevelFadeOut)));
	
	m_fColorLevel	= SATURATE(m_fColorLevelT);
	
	m_fFlickerFrequency = SATURATE(LERP(1.0f, 0.25f, m_fFlickerFrequencyT));

	//color fading, reacts to health immediately
	const	float	fSaturation		= m_pCriticalSaturation->GetParam();
	const	float	fContrast		= m_pCriticalContrast->GetParam();
	const	float	fBrightness		= m_pCriticalBrightness->GetParam();

	gcpRendD3D->EF_SetPostEffectParam("Global_User_Saturation", LERP(fSaturation, 1.0f, m_fColorLevel), true);
//	gcpRendD3D->EF_SetPostEffectParam("Global_User_Contrast", LERP(fContrast, 1.0, m_fColorLevel), true);
//	gcpRendD3D->EF_SetPostEffectParam("Global_User_Brightness", LERP(fBrightness, 1.0, m_fColorLevel), true);

	
	//hack to have hit areas disappear in armour mode	
	float	fAreaVisibility	= SATURATE(m_pHitAreaVisibility->GetParam());	//data in [0..1]
	float	fNanoGlassActive = 0;
	gcpRendD3D->EF_GetPostEffectParam("NanoGlass_Active", fNanoGlassActive);

	Vec4	vNanoGlassHex;
	gcpRendD3D->EF_GetPostEffectParamVec4("NanoGlass_Hex", vNanoGlassHex);
	float	fTargetTiling = m_pNanoPatternTiling->GetParam();

	if(fNanoGlassActive > 0)
	{
		fAreaVisibility	= 0.0f;
		//fTargetTiling	= vNanoGlassHex.x;		//disabled for now
	}
	const	float	fAreaVisDelta	= fAnimSpeed * fDeltaTime * 100.0f;
	const	float	fAreaVisDiff	= fAreaVisibility - m_fAreaVisibilityT;
	m_fAreaVisibilityT	+= min(fAreaVisDelta, abs(fAreaVisDiff)) * SIGN(fAreaVisDiff);
	m_fAreaVisibility	= SATURATE(m_fAreaVisibilityT);

	//feature: adjust pattern tiling in armour mode
	const	float	fTilingDelta	= fAnimSpeed * fDeltaTime * 2000.0f;
	const	float	fTilingDiff		= fTargetTiling - m_fTilingFactorT;
	m_fTilingFactorT	+= min(fTilingDelta, abs(fTilingDiff)) * SIGN(fTilingDiff);	
	m_fTilingFactor		= max(m_fTilingFactorT, 8.0f);
}

void	CHUDHitEffect::UpdateEffectLogic()
{
	//--- spawn hit effect
	SpawnHitEffect();

	//--- update coverage
	UpdateCoverage();

	//--- update health display
	UpdateHealth();
}

//bool	CHUDHitEffect::InitDynTexture(CTexture*& ptexRT, int nWidth, int nHeight)
//{	
//	return false;
//
//	////tricky, don't forget the &!	
//	//assert(nWidth);
//	//assert(nHeight);
//
//	//if((nWidth <= 0) && (nHeight <= 0))
//	//	return false;
//
//	//const bool bTexExists = CTexture::IsTextureExist(ptexRT);
//	//bool bTexOK = bTexExists;
//	//if (!bTexExists)
//	//{
//	//	bTexOK = ptexRT->Create2DTexture(nWidth, nHeight, 1, FT_DONT_RELEASE | FT_DONT_STREAM | FT_DONT_RESIZE | FT_USAGE_RENDERTARGET, 0, eTF_A8R8G8B8, eTF_A8R8G8B8);
//	//	if (bTexOK)
//	//	{
//	//		ColorF c = ColorF(0.0, 0.0, 0.0, 0.0);
//	//		ptexRT->Fill(c);
//	//		ptexRT->SetRenderTargetTile(1);
//	//		m_b1stFrame = true;
//	//	}
//	//}
//
//	//return bTexOK;
//}

//bool	CHUDHitEffect::CreateDynTextures()
//{
//	//HACK disable dynamic textures
//	return false;
//
	//int nWidth	= 128;	//256;
	//int nHeight	= 128;	//256;

	//bool bRes = true;
	//for(int i = 0; i < 2; ++i)
	//{
	//	bRes = bRes && InitDynTexture(CTexture::s_ptexHitAreaRT[i], nWidth, nHeight);		
	//}
	//return bRes;
//
//	return false;
//}

//void CHUDHitEffect::ReleaseDynTextures()
//{
//	////release dynamic textures
//	//SAFE_HINT_RELEASE(CTexture::s_ptexHitAreaRT[0]);
//	//SAFE_HINT_RELEASE(CTexture::s_ptexHitAreaRT[1]);
//}


void	CHUDHitEffect::RenderAttenuationPass(CTexture*& rptexPrevRT, int iViewportWidth, int iViewportHeight, int iRTWidth, int iRTHeight)
{
	PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_ATTENUATION_PASS" );
	//PostProcessUtils().CopyTextureToScreen(CTexture::s_ptexBlack);
	PostProcessUtils().ClearScreen(0,0,0,0);
	if(!m_b1stFrame)
	{
		const float	fDeltaTime(PostProcessUtils().m_pTimer->GetFrameTime());
		const float	fFrameAttenuation	= m_pHitAttenuation->GetParam() * 30.0f * fDeltaTime;
		const float fFrameBlurTCFactor	= m_pHitAttenuationBlur->GetParam() * 30.0f * fDeltaTime;
		const Vec4	vAttenuationParams(fFrameAttenuation, fFrameAttenuation, fFrameAttenuation, fFrameBlurTCFactor);
		const Vec4	vNoiseParams(-0.2f, 2.0f, 0.4f, -4.0f);
		CTexture*	pPrevTexture = rptexPrevRT;

// 		gcpRendD3D->Set2DMode(false, 0, 0);	//was iViewportWidth, iViewportHeight but who cares, reset 2d mode, params not used
// 		gcpRendD3D->Set2DMode(true, 1, 1);	//set 2d mode, orthographic matrix 1, 1

		PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, s_tnAttenuationPass, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
		gcpRendD3D->FX_SetState( GS_BLSRC_ONE | GS_BLDST_SRCCOL | GS_NODEPTHTEST);
		PostProcessUtils().ShSetParamPS( s_pnAttenuationParams, vAttenuationParams );
		PostProcessUtils().ShSetParamPS( s_pnNoiseParams, vNoiseParams );
		PostProcessUtils().SetTexture(pPrevTexture, 0, FILTER_LINEAR, TADDR_MIRROR);
		PostProcessUtils().SetTexture(m_ptexPerlinNoise, 1, FILTER_LINEAR, TADDR_MIRROR);
		PostProcessUtils().DrawFullScreenQuad(iRTWidth, iRTHeight);
		PostProcessUtils().ShEndPass();
	}	
	PROFILE_LABEL_POP( "HUD_HIT_EFFECT_ATTENUATION_PASS" );
}


void	CHUDHitEffect::RenderAccumulationPass(int iViewportWidth, int iViewportHeight, int iRTWidth, int iRTHeight)
{
	PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_ACCUM_PASS" );

	const float fRTScreenRatio		= static_cast<float>(iRTWidth) / static_cast<float>(iRTHeight);
	const float fRTScreenRatio_inv	= static_cast<float>(iRTHeight)/ static_cast<float>(iRTWidth);

	const float fVPScreenRatio		= static_cast<float>(iViewportWidth) / static_cast<float>(iViewportHeight);
	const float fVPScreenRatio_inv	= static_cast<float>(iViewportHeight)/ static_cast<float>(iViewportWidth);

// 	gcpRendD3D->Set2DMode(false, 1, 1);
// 	gcpRendD3D->Set2DMode(true, 1, 1);

	const Vec2	vScreenCenter(0.5f, 0.5f);
	const Vec2	vHitSize_half(0.5f, 0.5f);

	for(int i = 0; i < sm_HitImpactCount; ++i)
	{
		SHitImpact& hitImpact = m_aHitImpacts[i];
		if(hitImpact._bStarted)
		{
			//draw moving impact
			const float fHitImpactSize = max(hitImpact._fStrength * 0.0033f, 0.5f);
			const Vec2	vHitSize_strength(vHitSize_half.x * fVPScreenRatio_inv * fHitImpactSize, vHitSize_half.y * fHitImpactSize);
			const Vec2	vHitPosition_p	( hitImpact._vCurrentPosition.x * 0.5f + vScreenCenter.x, -hitImpact._vCurrentPosition.y * 0.5f + vScreenCenter.y );

			const Vec2	vHitTopLeft	( vHitPosition_p - vHitSize_strength );
			const Vec2	vHitBtmRight( vHitPosition_p + vHitSize_strength );
			const Vec4	vHitParams	(hitImpact._fStrength, hitImpact._fImpactSpeed, 1, 0);

			PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_ACCUM_IMPACT" );
			PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, s_tnHitAccumulationPass, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
			{
				gcpRendD3D->FX_SetState( GS_BLSRC_ONE | GS_BLDST_ONE | GS_NODEPTHTEST);
				PostProcessUtils().ShSetParamPS(s_pnHitParams, vHitParams);
				PostProcessUtils().SetTexture(m_ptexImpactRound, 0, FILTER_LINEAR, TADDR_CLAMP);
				PostProcessUtils().DrawScreenQuad(256, 256, vHitTopLeft.x, vHitTopLeft.y, vHitBtmRight.x, vHitBtmRight.y);
			}
			PostProcessUtils().ShEndPass();
			PROFILE_LABEL_POP( "HUD_HIT_EFFECT_ACCUM_IMPACT" );
		}
	}

	for(int i = 0; i < sm_HitImpactCount; ++i)
	{
		SHitImpact& hitImpact = m_aHitImpacts[i];
		if(hitImpact._bStarted && hitImpact._bFlashPosInited && hitImpact._fFlashDrawTime > 0)
		{
			//draw static flash (only once)
			const float fFlashSize = max(hitImpact._fStrength * 0.0066f, 0.5f);	//0.0033f, 0.5f);
			const Vec2	vFlashSize_strength(vHitSize_half.x * fVPScreenRatio_inv * fFlashSize, vHitSize_half.y * fFlashSize);
			const Vec2	vFlashPosition_p( hitImpact._vFlashPosition.x * 0.5f + vScreenCenter.x, -hitImpact._vFlashPosition.y * 0.5f + vScreenCenter.y );

			const Vec2	vFlashTopLeft	( vFlashPosition_p - vFlashSize_strength );
			const Vec2	vFlashBtmRight	( vFlashPosition_p + vFlashSize_strength );
			const Vec4	vFlashParams	(hitImpact._fStrength, hitImpact._fImpactSpeed, 0, 1);

			PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_ACCUM_FLASH" );
			PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, s_tnFlashAccumulationPass, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
			{
				gcpRendD3D->FX_SetState( GS_BLSRC_ONE | GS_BLDST_ONE | GS_NODEPTHTEST);
				PostProcessUtils().ShSetParamPS(s_pnHitParams, vFlashParams);
				PostProcessUtils().SetTexture(m_ptexImpactRound, 0, FILTER_LINEAR, TADDR_CLAMP);
				PostProcessUtils().DrawScreenQuad(256, 256, vFlashTopLeft.x, vFlashTopLeft.y, vFlashBtmRight.x, vFlashBtmRight.y);
			}
			PostProcessUtils().ShEndPass();
			PROFILE_LABEL_POP( "HUD_HIT_EFFECT_ACCUM_FLASH" );
		}
	}	
	PROFILE_LABEL_POP( "HUD_HIT_EFFECT_ACCUM_PASS" );
}


void	CHUDHitEffect::RenderDisplayPass(CTexture*& rptexCurrRT, int iViewportWidth, int iViewportHeight)
{
	PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_DISPLAY_PASS" );

	const float fHealthLevel	= m_pHealthLevel->GetParam();
	const Vec4	vHealthParams(fHealthLevel, m_fNanoLevel, m_fVeinsLevel, m_fAreaVisibility);	
	const Vec4	vDisplayParams(m_fFlickerFrequency, m_fTilingFactor, m_fTilingFactor * 0.1f, 0);

	const Vec4	vScreenBorder(
		m_pScreenBorderLeft->GetParam(),
		m_pScreenBorderTop->GetParam(),
		m_pScreenBorderRight->GetParam(),
		m_pScreenBorderBottom->GetParam());

	if( CRenderer::CV_r_HUDHitEffect == 11 )
	{
		// Disable orthographic projection for real geometry case..
  	gcpRendD3D->Set2DMode(false, 1, 1);
	}

	//NanoPattern health display	
	uint64	uiPrevShaderFlag = gRenDev->m_RP.m_FlagsShader_RT;
	gRenDev->m_RP.m_FlagsShader_RT &= ~( 
		g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1]	| g_HWSR_MaskBit[HWSR_SAMPLE2]	|
		g_HWSR_MaskBit[HWSR_SAMPLE3] | g_HWSR_MaskBit[HWSR_SAMPLE4] | g_HWSR_MaskBit[HWSR_SAMPLE5]	|
		g_HWSR_MaskBit[HWSR_DEBUG0]	 | g_HWSR_MaskBit[HWSR_DEBUG1]	| g_HWSR_MaskBit[HWSR_DEBUG2]	| g_HWSR_MaskBit[HWSR_DEBUG3]	);

	gRenDev->m_RP.m_FlagsShader_RT |= (CRenderer::CV_r_HUDHitEffect == 7) ? g_HWSR_MaskBit[HWSR_DEBUG0] : 0;

	PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT_HEALTH_DISPLAY" );
	PostProcessUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, s_tnHealthDisplayPass, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);	
	
	gcpRendD3D->FX_SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST);

	PostProcessUtils().ShSetParamPS( s_pnDisplayParams, vDisplayParams );
	PostProcessUtils().ShSetParamPS( s_pnHealthParams, vHealthParams );	

	PostProcessUtils().SetTexture(rptexCurrRT, 0, FILTER_LINEAR);

	PostProcessUtils().SetTexture(m_ptexNanoPatternLine, 1, FILTER_LINEAR, TADDR_WRAP);
	PostProcessUtils().SetTexture(m_ptexVeinsBlood, 2, FILTER_LINEAR, TADDR_CLAMP, true);

	PostProcessUtils().SetTexture(m_ptexHealthGradient, 3, FILTER_LINEAR, TADDR_CLAMP);
	PostProcessUtils().SetTexture(m_ptexVignetteAreas, 4, FILTER_LINEAR, TADDR_MIRROR);

	static bool s_bMode3Border = false;
	s_bMode3Border = !s_bMode3Border;
	switch(CRenderer::CV_r_HUDHitEffect)
	{
	case 1:	//iViewportWidth, iViewportHeight
		PostProcessUtils().DrawFullScreenBorder(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight(), vScreenBorder, false);
		break;

	case 2:
		PostProcessUtils().DrawFullScreenBorder(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight(), vScreenBorder, true);
		break;

	case 3:	//debug: errors should become visible by flipping rendering type each frame		
		PostProcessUtils().DrawFullScreenBorder(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight(), vScreenBorder, s_bMode3Border);	//<-- proved to be working
		break;

	case 11:
		DrawGeometry(&m_pRenderData, CShaderMan::m_shPostEffectsGame, s_tnHealthDisplayPass);
		break;

	default:
		PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());
		break;
	}

	PostProcessUtils().ShEndPass();

	gRenDev->m_RP.m_FlagsShader_RT = uiPrevShaderFlag;
	PROFILE_LABEL_POP( "HUD_HIT_EFFECT_HEALTH_DISPLAY" );
	PROFILE_LABEL_POP( "HUD_HIT_EFFECT_DISPLAY_PASS" );

#ifdef _DEBUG
	if(CRenderer::CV_r_HUDHitEffect > 4)
	{
		gcpRendD3D->TextToScreen(1,40, 
			"[hit effect]: \n"
			" health level: %f\n"		
			" nano level: %f (%f)\n"
			" veins level: %f (%f)\n"
			" color level: %f (%f)\n"
			" flicker frequency: %f (%f)\n"
			" area visibility: %f (%f)\n"
			" tiling factor: %f (%f)\n"
			" vHealthParams {%f %f %f %f}\n"
			" vDisplayParams {%f %f %f %f}\n",
			fHealthLevel,
			m_fNanoLevel, m_fNanoLevelT,
			m_fVeinsLevel, m_fVeinsLevelT,
			m_fColorLevel, m_fColorLevelT,
			m_fFlickerFrequency, m_fFlickerFrequencyT,
			m_fAreaVisibility, m_fAreaVisibilityT,
			m_fTilingFactor, m_fTilingFactorT,
			vHealthParams.x, vHealthParams.y, vHealthParams.z, vHealthParams.w,
			vDisplayParams.x, vDisplayParams.y, vDisplayParams.z, vDisplayParams.w);
	}
#endif

	if( CRenderer::CV_r_HUDHitEffect == 11 )
	{
		// Restore orthographic projection for further post processes
		gcpRendD3D->Set2DMode(true, 1, 1);
	}
}


void	CHUDHitEffect::Render()
{
	UpdateEffectLogic();

	//HACK - disable effect being rendered
	return;

	//gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);

	//PROFILE_LABEL_PUSH( "HUD_HIT_EFFECT" );
	//PROFILE_SHADER_START

	//int iViewportX, iViewportY, iViewportWidth, iViewportHeight;
	//gcpRendD3D->GetViewport(&iViewportX, &iViewportY, &iViewportWidth, &iViewportHeight);
	//
	//uint16	uPrevDytex	= (m_uCurrentDytex + 1) % 2;
	//CTexture*&	rpPrevDytex = CTexture::s_ptexHitAreaRT[uPrevDytex];
	//assert(rpPrevDytex);	
	//CTexture*&	rpCurrDytex = CTexture::s_ptexHitAreaRT[m_uCurrentDytex];
	//assert(rpCurrDytex);	
	//int		iDytexWidth	= rpCurrDytex->GetWidth();
	//int		iDytexHeight= rpCurrDytex->GetHeight();

	//gcpRendD3D->FX_PushRenderTarget(0, rpCurrDytex, PostProcessUtils().m_pCurDepthSurface);
	//gcpRendD3D->RT_SetViewport(0, 0, iDytexWidth, iDytexHeight);
	//{
	//	//clean or attenuate pass
	//	RenderAttenuationPass(rpPrevDytex, iViewportWidth, iViewportHeight, iDytexWidth, iDytexHeight);	

	//	//cumulate hit effect areas
	//	RenderAccumulationPass(iViewportWidth, iViewportHeight, iDytexWidth, iDytexHeight);
	//}
	//gcpRendD3D->RT_SetViewport(iViewportX, iViewportY, iViewportWidth, iViewportHeight);
	//gcpRendD3D->FX_PopRenderTarget(0);

	////display pass
	//RenderDisplayPass(rpCurrDytex, iViewportWidth, iViewportHeight);
	//
	//m_uCurrentDytex = (m_uCurrentDytex + 1) % 2;


	//PROFILE_SHADER_END
	//PROFILE_LABEL_POP( "HUD_HIT_EFFECT" );
	//
	////flush
	//gcpRendD3D->FX_Flush();

	//m_b1stFrame = false;
}

//////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CPostEffect::DrawGeometry(SRenderDataAr* pRenderDataAr, CShader* pShader, const CCryNameTSCRC& nameTech)
{
	if(!(pRenderDataAr && pShader))
		return;

	SShaderTechnique* pShaderTech = pShader->mfFindTechnique(nameTech);
	if(!pShaderTech)
		return;

	//gcpRendD3D
	const uint32 nThreadID = gcpRendD3D->m_RP.m_nProcessThreadID;
	SRenderData* pRenderData = (&*pRenderDataAr[nThreadID]);	

	if(!pRenderData && !(pRenderData->pRenderElement))
		return;

	SRenderData& rRenderData = *pRenderData;

	// Set scissor
	gcpRendD3D->FX_Commit(); 
	gcpRendD3D->EF_Scissor(true, 0, 0, gcpRendD3D->GetWidth(), gcpRendD3D->GetHeight());

	// Set cull mode
	gcpRendD3D->SetCullMode( R_CULL_BACK );

	// Draw mesh
	CD3D9Renderer *const __restrict rd = gcpRendD3D;
	CREMeshImpl *pRenderMesh = (CREMeshImpl*) pRenderData->pRenderElement;

	if(pRenderMesh)
	{
		// Create/Update vertex buffer stream
		if( pRenderMesh->m_pRenderMesh )
			pRenderMesh->m_pRenderMesh->CheckUpdate( pRenderMesh->m_pRenderMesh->_GetVertexFormat(), 0);

		gcpRendD3D->m_RP.m_pRE = const_cast<CRendElementBase*>( pRenderData->pRenderElement );
		if( gcpRendD3D->FX_CommitStreams(&pShaderTech->m_Passes[0], true) )
		{
			gcpRendD3D->m_RP.m_FirstVertex = pRenderMesh->m_nFirstVertId;
			gcpRendD3D->m_RP.m_FirstIndex = pRenderMesh->m_nFirstIndexId;
			gcpRendD3D->m_RP.m_RendNumIndices = pRenderMesh->m_nNumIndices;
			gcpRendD3D->m_RP.m_RendNumVerts = pRenderMesh->m_nNumVerts;
			gcpRendD3D->m_RP.m_pRE->mfDraw(pShader, &pShaderTech->m_Passes[0]);
		}
	}
	//reset modes
	gcpRendD3D->EF_Scissor(false, 0, 0, 0, 0);
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CScreenBlood::Render()
{
	PROFILE_LABEL_PUSH( "SCREEN BLOOD" );

	static CCryNameTSCRC pTechName("ScreenBlood");
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES);   
	gcpRendD3D->FX_SetState(GS_NODEPTHTEST| GS_BLSRC_DSTCOL | GS_BLDST_SRCALPHA);     

	Vec4 pParams= Vec4(0, 0, 0, max(0.2f, 1.0f - m_pAmount->GetParam()));
	static CCryNameR pParamName("psParams");
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName, &pParams, 1);
	GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

	GetUtils().ShEndPass();   

	//m_nRenderFlags = PSP_UPDATE_BACKBUFFER;  

	PROFILE_LABEL_POP( "SCREEN BLOOD" );
}


/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CScreenGlassShards::Render()
{
	PROFILE_LABEL_PUSH( "GLASS SHARDS" );

	static CCryNameTSCRC pTechName("ScreenGlassShards");
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES);   
	gcpRendD3D->FX_SetState(GS_NODEPTHTEST| GS_BLSRC_ONE | GS_BLDST_ZERO);     

	Vec4 pParams= Vec4(0, 0, 0, max(0.2f, 1.0f - m_pAmount->GetParam()));
	static CCryNameR pParamName("psParams");
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName, &pParams, 1);
	GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

	GetUtils().ShEndPass();   

	PROFILE_LABEL_POP( "GLASS SHARDS" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

int CScreenFog::CreateResources()
{
	return 0;
}

void CScreenFog::Release()
{
}

void CScreenFog::Render()
{
	PROFILE_LABEL_PUSH( "SCREEN FOG" );

	const CCryNameTSCRC pTechName("ScreenFog");
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, pTechName, FEF_DONTSETSTATES);
	gcpRendD3D->FX_SetState(GS_NODEPTHTEST | GS_BLSRC_ONEMINUSSRCALPHA | GS_BLDST_SRCALPHA);

	Vec4 pParams(m_pFogColor->GetParamVec4());
	pParams.w = m_pAmount->GetParam();
	const CCryNameR pParamName("ScreenFog_Params");
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName, &pParams, 1);
	
	GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

	GetUtils().ShEndPass();   

	PROFILE_LABEL_POP( "SCREEN FOG" );
}



void CScreenFog::Update()
{
}


////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

